import random

import requests

from web import models
from django import forms
from utils.encrypt import md5
from BugManage import settings
from utils.tencent.sms import send_sms_single
from django_redis import get_redis_connection
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from utils.BootStrap import BootStrapForm, BootStrapModelForm


class RegisterModelForm(BootStrapModelForm):
    password = forms.CharField(label="密码", min_length=6, max_length=16,
                               error_messages={"min_length": "密码长度不得小于6位", "max_length": "密码长度不得大于16位"},
                               widget=forms.PasswordInput(render_value=True))
    confirm_pwd = forms.CharField(label='确认密码', min_length=6, max_length=16,
                                  error_messages={"min_length": "密码长度不得小于6位", "max_length": "密码长度不得大于16位"},
                                  widget=forms.PasswordInput(render_value=True))  # render_value=True设置是否保留输入框数据
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误')])
    code = forms.CharField(label="验证码", widget=forms.TextInput())

    class Meta:
        model = models.UserInfo
        fields = ["username", "email", "password", "confirm_pwd", "mobile_phone", "code"]

    def clean_username(self):  # 判断用户名是否重复
        username = self.cleaned_data['username']
        exist = models.UserInfo.objects.filter(username=username).exists()
        if exist:
            raise ValidationError("用户名已存在")
        return username

    def clean_email(self):  # 判断邮箱是否存在
        emai = self.cleaned_data["email"]
        exit = models.UserInfo.objects.filter(email=emai).exists()
        if exit:
            raise ValidationError("邮箱已存在")
        return emai

    def clean_password(self):  # 对用户输入密码进行加密
        pwd = self.cleaned_data["password"]
        return md5(pwd)

    def clean_confirm_pwd(self):  # 进行密码对比，对确认密码也加密
        pwd = self.cleaned_data.get('password')
        confim = self.cleaned_data['confirm_pwd']
        if md5(confim) != pwd:
            raise ValidationError("两次密码不一致")
        return md5(confim)

    def clean_mobile_phone(self):  # 判断手机号是否注册
        phone = self.cleaned_data['mobile_phone']
        exit = models.UserInfo.objects.filter(mobile_phone=phone).exists()
        if exit:
            raise ValidationError("当前手机号已注册")
        return phone

    def clean_code(self):  # 进行验证码验证
        code = self.cleaned_data['code']
        phone = self.cleaned_data.get("mobile_phone")
        if not phone: # 如果手机号没获取到，说明手机号那抛错了，验证码不处理就直接返回就行。
            return code

        conn = get_redis_connection()
        redis_code = conn.get(phone)
        if not redis_code:
            raise ValidationError("验证码失效")
        if code != redis_code.decode("utf-8"):
            raise ValidationError("验证码错误")
        return code


class SmsForm(forms.Form):
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误')])

    # 上面的正则会进行手机号格式判断
    def __init__(self, request, *args, **kwargs):  # 为子类新增一个参数
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        # 获取到用户填的手机号
        mobile_phone = self.cleaned_data['mobile_phone']  # 前端传来值的name需要和字段名保持一致
        # 1.去判断模板短信模板是否正确
        type = self.request.GET.get("type")
        tem_id = settings.SMS_TEMPLATE_ID.get(type)
        if not tem_id:
            raise ValidationError("模板错误")
        # 2.去判断数据库是否存在此手机号(逻辑：需满足当注册时手机号不存在，登陆时手机号存在才允许发短信)
        tel_obj = models.UserInfo.objects.filter(mobile_phone=mobile_phone).first()
        if type == "register":
            if tel_obj:
                raise ValidationError("手机号已注册")
        elif type == "login":
            if not tel_obj:
                raise ValidationError("手机号还未注册")
        # 3.上述问题不存在进行发送短信
        code = random.randrange(1000, 9999)
        print(code)
        res = send_sms_single(mobile_phone, tem_id, [code, ])
        print(res)
        if res["result"] != 0:  # 4.判断腾讯云返回的结果，失败也抛错
            raise ValidationError("短信发送失败，{}".format(res["errmsg"]))
        # 上述错误都不存在，这里就发送短信成功，将验证码写入redis
        conn = get_redis_connection()
        conn.set(mobile_phone, code)  # 可加ex=60设置验证码效期60秒，暂时没设置
        return mobile_phone


class LoginPwdForm(BootStrapForm):
    username = forms.CharField(label='用户名或邮箱', widget=forms.TextInput)
    password = forms.CharField(label="密码", widget=forms.PasswordInput(render_value=True))
    code = forms.CharField(label="验证码")

    def __init__(self, request, *args, **kwargs):  # 为子类新增一个request参数
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_username(self):
        username = self.cleaned_data["username"]
        user_obj1 = models.UserInfo.objects.filter(username=username).first()
        user_obj2 = models.UserInfo.objects.filter(email=username).first()
        if not user_obj1 and not user_obj2:
            raise ValidationError("此用户名和邮箱都不存在")
        return username

    def clean_password(self):
        pwd = self.cleaned_data["password"]
        return md5(pwd)

    def clean_code(self):
        code = self.cleaned_data["code"]
        sesion_code = self.request.session.get('img_code')
        if not sesion_code:
            raise ValidationError("验证码失效，请重新获取")
        if code.strip().upper() != sesion_code.upper(): # strip()去除空格
            raise ValidationError("验证码错误")
        return code

class LoginMsgForm(BootStrapForm):
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误')],
                                   widget=forms.TextInput)
    code = forms.CharField(label="验证码", widget=forms.TextInput)

    def clean_mobile_phone(self):
        mobiel_phone = self.cleaned_data['mobile_phone']
        exits = models.UserInfo.objects.filter(mobile_phone=mobiel_phone).exists()
        if not exits:
            raise ValidationError("当前手机号未注册")
        return  mobiel_phone

    def clean_code(self):
        code = self.cleaned_data["code"]
        mobiel_phone = self.cleaned_data.get("mobile_phone")
        if not mobiel_phone: # 当上面手机号有错误时，此处直接返回code，以免给下方传入空值
            return code
        conn = get_redis_connection()
        redis_code = conn.get(mobiel_phone)
        if not redis_code:
            raise ValidationError("验证码失效或还未获取")
        if code != redis_code.decode("utf-8"):
            raise ValidationError("验证码错误")
        return code
